package com.swak.frame.ratelimit.spring.configuration;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;

import com.swak.frame.cache.CacheProxy;
import com.swak.frame.ratelimit.LimitType;
import com.swak.frame.ratelimit.RateLimitAnnotationParser;
import com.swak.frame.ratelimit.SwakRateLimiter;
import com.swak.frame.ratelimit.adapter.LimitRaterAdapter;
import com.swak.frame.ratelimit.adapter.LimitRaterFactoryAdapter;
import com.swak.frame.ratelimit.interceptor.RateLimitInterceptor;
import com.swak.frame.ratelimit.interceptor.RaterAnnotationBeanPostProcessor;
import com.swak.frame.ratelimit.interceptor.RaterAnnotationParserComposite;
import com.swak.frame.ratelimit.interceptor.RaterOperationSource;
import com.swak.frame.ratelimit.interceptor.SpringRaterOperationSource;
import com.swak.frame.ratelimit.parser.LimitRaterAnnotationParser;
import com.swak.frame.ratelimit.parser.LimitRaterFilterAnnotationParser;
import com.swak.frame.ratelimit.resolver.LocalTokenLimitRater;
import com.swak.frame.ratelimit.resolver.RedisLimitRater;

public class ProxyRateLimitConfiguration extends AbstractRateLimitConfiguration {

	@Autowired(required = false)
	private CacheProxy cacheProxy;

	@Bean
	@ConditionalOnMissingBean(SwakRateLimiter.class)
	public SwakRateLimiter swakLimitRater() {
		SwakRateLimiter limitRater = null;
		LimitType limitType = rateLimitPropertie.getType();
		// 限流类型
		if (LimitType.REDIS.equals(limitType)) {
			limitRater = new RedisLimitRater(cacheProxy);
		} else if (LimitType.LOCAL_TOKEN.equals(limitType)) {
			limitRater = new LocalTokenLimitRater();
		}
		return limitRater;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	@ConditionalOnMissingBean(LimitRaterFilterAnnotationParser.class)
	public RateLimitAnnotationParser limitRaterFilterAnnotationParser() {
		LimitRaterFilterAnnotationParser limitRaterFilterAnnotationParser = new LimitRaterFilterAnnotationParser();
		limitRaterFilterAnnotationParser.setSystemConfig(systemConfig);
		return limitRaterFilterAnnotationParser;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	@ConditionalOnMissingBean(LimitRaterAnnotationParser.class)
	public RateLimitAnnotationParser limitRaterAnnotationParser() {
		LimitRaterAnnotationParser limitRaterAnnotationParser = new LimitRaterAnnotationParser();
		return limitRaterAnnotationParser;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	@ConditionalOnMissingBean(RaterOperationSource.class)
	public RaterOperationSource raterOperationSource(List<RateLimitAnnotationParser> rateLimitAnnotationParsers) {
		RaterAnnotationParserComposite composite = new RaterAnnotationParserComposite(rateLimitAnnotationParsers);
		SpringRaterOperationSource raterOperationSource = new SpringRaterOperationSource(composite);
		if (this.rateLimitPropertie != null) {
			raterOperationSource.setDynamic(this.rateLimitPropertie.isDynamic());
			raterOperationSource.setLimitType(this.rateLimitPropertie.getType());
		}
		return raterOperationSource;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	@ConditionalOnMissingBean(RateLimitInterceptor.class)
	public RateLimitInterceptor rateLimitInterceptor(RaterOperationSource raterOperationSource,
			LimitRaterAdapter limitRaterAdapter) {
		RateLimitInterceptor interceptor = new RateLimitInterceptor();
		interceptor.setOperationSource(raterOperationSource);
		interceptor.setLimitRaterAdapter(limitRaterAdapter);
		return interceptor;
	}

	@Bean("internalSwakRateLimitAdvisor")
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	@ConditionalOnMissingBean(RaterAnnotationBeanPostProcessor.class)
	public RaterAnnotationBeanPostProcessor rateLimitAdvisor(RateLimitInterceptor rateLimitInterceptor) {
		RaterAnnotationBeanPostProcessor rateLimitAdvisor = new RaterAnnotationBeanPostProcessor(rateLimitInterceptor);
		if (this.rateLimitPropertie != null) {
			rateLimitAdvisor.setOrder(rateLimitPropertie.getOrder());
		}
		return rateLimitAdvisor;
	}

	@Bean
	@ConditionalOnMissingBean(LimitRaterAdapter.class)
	public LimitRaterAdapter limitRaterAdapter(SwakRateLimiter swakRateLimiter) {
		LimitRaterFactoryAdapter limitRaterAdapter = new LimitRaterFactoryAdapter();
		limitRaterAdapter.setSwakRateLimiter(swakRateLimiter);
		return limitRaterAdapter;
	}

}
